<?php
namespace Felixji\LogicHandler;
/**
 * 逻辑代码字符串解析类
 * 'Q1 + Q2 > 3 And Q1 == 2 And (Qs3_2 < 1 Or Count[Qn2] != 3)  Do  Goto[Q4],Assign[Q2,1]   '
 * ''
 */
class LogicStringHandler
{
    private static $_model;
    //动作分隔符
    private $action_separator = 'DO';
    private $or_separator = 'Or';
    private $and_separator = 'And';
    private $str_logics;
    private $str_condition;
    private $str_action;

    const PatternFunction = '/([A-z]+)\[(.*)\]/U';
    const PatternBracket = '/\([^\(]*\)/U';
    const PatternQuestion = '/Q\w+/';
    const Expression = ['==', '!=', '>', '<', '>=', '<=', '><'];
    const Operate = ['*', '/', '+', '-'];


    /**
     * @return LogicStringHandler
     */
    public static function model(): LogicStringHandler
    {
        if (is_null(self::$_model)) {
            self::$_model = new self();
        }
        return self::$_model;
    }

    private function __construct()
    {
    }

    private function __clone()
    {
    }

    public function setActionSeparator(string $s)
    {
        $this->action_separator = $s;
    }

    public function setLogicStr(string $str)
    {
        $this->str_logics = $str;
        $this->explode();
    }

    public function explode()
    {
        $str = $this->str_logics;
        if (is_string($str)) {
            $arr = explode(" {$this->action_separator} ", $str);
            if (count($arr) == 2) {
                $this->setActionStr($arr[1]);
                $this->setConditionStr($arr[0]);
            } else {
                $this->setActionStr($arr[0]);
            }
        }
    }

    public function getConditionStr()
    {
        return $this->str_condition;
    }

    public function getActionStr()
    {
        return $this->str_action;
    }

    public function setConditionStr(string $str)
    {
        $this->str_condition = $str;
    }

    public function setActionStr(string $str)
    {
        $this->str_action = $str;
    }

    private function condition(): bool
    {
        $condition = $this->str_condition;
        if (empty($condition))
            return true;

        //匹配函数
        if (preg_match_all(self::PatternFunction, $condition, $matches1)) {
            //var_dump($matches);
            foreach ($matches1[0] as $match) {
                //替换函数执行结果 $match=>$value  Count[Qn2] = 100
                $value = 100;
                $condition = str_replace($match, $value, $condition);
            }
        }
        //匹配小括号
//        if(preg_match_all(self::PatternBracket,$condition,$matches2)){
//
//            foreach ($matches2[0] as $match2){
//                $value = 200;
//                $condition = str_replace($match2,$value,$condition);
//            }
//
//        }
//        var_dump($condition);
        while (preg_match_all(self::PatternBracket, $condition, $matches2)) {
            foreach ($matches2[0] as $match2) {
                $value = $this->conditionNormal($match2);
                $condition = str_replace($match2, $value, $condition);
            }
        }
        return boolval($this->conditionNormal($condition));

//        return false;
    }

    private function conditionNormal($condition)
    {

        $condition = str_replace(['(', ')'], '', $condition);
        $condition = trim($condition);
        $or = " {$this->or_separator} ";
        $and = " {$this->and_separator} ";
        var_dump($condition);
        if (strpos($condition, $or) !== false) {
            $conditions = explode($or, $condition);
            foreach ($conditions as $c) {

                if (boolval($this->conditionNormal($c))) {
                    return 1;
                }
            }
            return 0;
        }
        if (strpos($condition, $and) !== false) {
            $conditions = explode($and, $condition);
            foreach ($conditions as $c) {
                if (!boolval($this->conditionNormal($c))) {
                    return 0;
                }
            }
            return 1;
        }
        //  == != > < >= <= ><
        foreach (self::Expression as $exp) {
            if (strpos($condition, $exp) !== false) {
                $conditions = explode($exp, $condition);
                $left = $this->conditionNormal($conditions[0]);
                $right = $this->conditionNormal($conditions[1]);
                switch ($exp) {
                    case '==':
                        return $left == $right;
                    case '!=':
                    case '><':
                        return $left != $right;
                    case '>=':
                        return $left >= $right;
                    case '<=':
                        return $left <= $right;
                    case '>':
                        return $left > $right;
                    case '<':
                        return $left < $right;
                }
            }
        }


        //+ - * /
        foreach (self::Operate as $op) {
            if (strpos($condition, $op) !== false) {
                $conditions = explode($op, $condition);
                $left = $this->conditionNormal($conditions[0]);
                $right = $this->conditionNormal($conditions[1]);
                switch ($op) {
                    case '+':
                        return $left + $right;
                    case '-':
                        return $left - $right;
                    case '*':
                        return $left * $right;
                    case '/':
                        return $right != 0 ? $left / $right : 0;
                }
            }
        }

        //处理题号
        if (preg_match(self::PatternQuestion, $condition, $matches)) {
            //Qs1
            return $this->getQuestionValue($matches[0]);
        }

        return $condition;
    }

    //Goto[Q4],Assign[Q2,1]
    private function action()
    {
        $action = $this->str_action;
        if (preg_match_all(self::PatternFunction, $action, $matches)) {
            foreach ($matches[1] as $k => $method) {
                $this->actionMethod($method, $matches[2][$k] ?: null);
            }
        }


    }

    private function actionMethod($method, $params = null)
    {
        $methodName = $method . 'Action';
        if (method_exists($this, $methodName)) {
            call_user_func([$this, $methodName], $params);
        } else {
            //echo $method.' not exist!';
        }
    }

    private function TestAction($str)
    {
//        echo 'Do -> TestAction '.$str;
    }

    private function conditionMethod($method, $params = null)
    {
        $methodName = $method . 'Condition';
        if (method_exists($this, $methodName)) {
            return call_user_func([$this, $methodName], $params);
        } else {
            //echo $method.' not exist!';
            return 0;
        }
    }

    /**
     * 获取题目的答案
     * @param string $question 题号
     * @return mixed 答案
     */
    private function getQuestionValue(string $question)
    {
        $value = rand(1, 99);
        var_dump($question . '：' . $value);
        return $value;
    }


    public function execute($str = null)
    {
        if ($str) {
            $this->setLogicStr($str);
        }
        if ($this->condition()) {
            echo '执行action';
            $this->action();
        } else {
            echo '未执行action';
        }
    }
}